import { Vector3, Box3, Mesh } from 'three';

/**
 * 爆炸方法封装
 * 使用方法：
 * 1、调用setSplitModel函数将要拆分的模型传入预处理
 * 然后两种控制爆炸方式
 * （1）实时更新
 *      调用startSplit()/quitSplit()函数开始爆炸/恢复
 *      需要在three的animate函数中调用update函数
 * （2）滑动条
 *      调用setValue函数把滑动条的值传入。
 */
export class ModelSplit {
    constructor({ mode = 2, splitScale = 5, splitSpeed = 100, meshList = [] } = {}) {
        this.meshList = meshList;
        this.running = false;
        this.targetSplitValue = 0;
        this.currentSplitValue = 0;
        this.offset = 1;
        this.splitScale = splitScale; //影响拆分距离，就是mesh的包围盒中心与爆炸中心的距离的倍率
        this.splitSpeed = splitSpeed; //影响拆分速度，反比例
        this.mode = mode;
        if (this.mode == 2) {
            this.splitScale = 0.3; //影响拆分距离，就是mesh的包围盒中心与爆炸中心的距离的倍率
            this.splitSpeed = 50; //影响拆分速度，反比例
        }
    }

    setSplitModel(model, data) {
        if (!model || model instanceof Mesh) {
            console.warn('只能处理Scene、Object3D、Group');
            return;
        }
        this.quit();
        //计算模型整体包围盒中心作为爆炸中心
        model.updateMatrixWorld();
        var box = new Box3().expandByObject(model);
        var maxLength = box.max.clone().distanceTo(box.min);
        var center;
        if (this.mode == 1) {
            center = box.getCenter(new Vector3());
        } else {
            //爆炸中心由子mesh的包围盒中心决定
            center = new Vector3();
            var subBox,
                subCenter,
                count = 0;
            model.traverse((node) => {
                if (node.type == 'Mesh') {
                    //分别计算每个mesh的包围盒中心，其与爆炸中心连线作为爆炸方向
                    subBox = new Box3().expandByObject(node);
                    subCenter = subBox.getCenter(new Vector3());
                    center = center.clone().add(subCenter);
                    count++;
                }
            });
            center = center.clone().multiplyScalar(1 / count);
        }
        if (this.meshList.length) {
            this.meshList.map((node) => {
                //分别计算每个mesh的包围盒中心，其与爆炸中心连线作为爆炸方向
                let subBox = new Box3().expandByObject(node);
                let meshCenter = subBox.getCenter(new Vector3());
                node._splitSrcPos = node.getWorldPosition(new Vector3());
                let subSpeed;
                if (this.mode == 1) {
                    subSpeed = {
                        x: ((meshCenter.x - center.x) * this.splitScale) / this.splitSpeed,
                        y: ((meshCenter.y - center.y) * this.splitScale) / this.splitSpeed,
                        z: ((meshCenter.z - center.z) * this.splitScale) / this.splitSpeed,
                    };
                } else {
                    let targetPos = meshCenter.clone().add(meshCenter.clone().sub(center).normalize().multiplyScalar(maxLength));
                    //这里计算各个轴向分速度，这样可以使用滑动条控制进度
                    subSpeed = {
                        x: ((targetPos.x - center.x) * this.splitScale) / this.splitSpeed,
                        y: ((targetPos.y - center.y) * this.splitScale) / this.splitSpeed,
                        z: ((targetPos.z - center.z) * this.splitScale) / this.splitSpeed,
                    };
                }
                node._splitSpeed = subSpeed;
            });
        } else {
            model.traverse((node) => {
                if (node.type == 'Mesh') {
                    //分别计算每个mesh的包围盒中心，其与爆炸中心连线作为爆炸方向
                    let subBox = new Box3().expandByObject(node);
                    let meshCenter = subBox.getCenter(new Vector3());
                    node._splitSrcPos = node.getWorldPosition(new Vector3());

                    let subSpeed;
                    if (this.mode == 1) {
                        subSpeed = {
                            x: ((meshCenter.x - center.x) * this.splitScale) / this.splitSpeed,
                            y: ((meshCenter.y - center.y) * this.splitScale) / this.splitSpeed,
                            z: ((meshCenter.z - center.z) * this.splitScale) / this.splitSpeed,
                        };
                    } else {
                        let targetPos = meshCenter.clone().add(meshCenter.clone().sub(center).normalize().multiplyScalar(maxLength));
                        //这里计算各个轴向分速度，这样可以使用滑动条控制进度
                        subSpeed = {
                            x: ((targetPos.x - center.x) * this.splitScale) / this.splitSpeed,
                            y: ((targetPos.y - center.y) * this.splitScale) / this.splitSpeed,
                            z: ((targetPos.z - center.z) * this.splitScale) / this.splitSpeed,
                        };
                    }

                    node._splitSpeed = subSpeed;
                    this.meshList.push(node);
                }
            });
        }
        this.currentSplitValue = 0;
        this.targetSplitValue = 0;
        this.running = false;
    }

    /**
     * 开始爆炸
     */
    startSplit() {
        this.targetSplitValue = this.splitSpeed;
        this.currentSplitValue = 0;
        this.offset = 1;
        this.running = true;
        this.isQuit = false;
    }

    /**
     * 开始反向爆炸（还原）
     */
    quitSplit() {
        this.targetSplitValue = 0;
        this.currentSplitValue = this.splitSpeed;
        this.offset = -1;
        this.running = true;
        this.isQuit = true;
    }

    /**
     * 退出拆分时还原
     */
    quit() {
        if (this.currentSplitValue != 0 && this.meshList.length > 0) {
            for (var i = 0; i < this.meshList.length; i++) {
                let node = this.meshList[i];
                node.position.copy(node._splitSrcPos);
            }
            this.currentSplitValue = 0;
            this.targetSplitValue = 0;
        }
    }

    /**
     * 如果用滑动条控制时将滑动条的值传入这个函数
     * @param {*} value [0,1]的值，表示爆炸进度
     */
    setValue(value) {
        if (value < 0) value = 0;
        if (value > 1) value = 1;
        this.currentSplitValue = value * this.splitSpeed;
        for (var i = 0; i < this.meshList.length; i++) {
            let node = this.meshList[i];
            let x = node._splitSpeed.x * this.currentSplitValue + node._splitSrcPos.x;
            let y = node._splitSpeed.y * this.currentSplitValue + node._splitSrcPos.y;
            let z = node._splitSpeed.z * this.currentSplitValue + node._splitSrcPos.z;
            node.parent.updateMatrixWorld();
            let invMat = node.parent.matrixWorld.clone().invert();
            let pos = new Vector3(x, y, z).applyMatrix4(invMat);
            node.position.copy(pos);
        }
    }

    /**
     * 更新
     * @returns
     */
    update() {
        if (this.running && this.meshList.length > 0) {
            if (this.currentSplitValue != this.targetSplitValue) {
                this.currentSplitValue += this.offset;
            }
            for (var i = 0; i < this.meshList.length; i++) {
                let node = this.meshList[i];
                let x = node._splitSpeed.x * this.currentSplitValue + node._splitSrcPos.x;
                let y = node._splitSpeed.y * this.currentSplitValue + node._splitSrcPos.y;
                let z = node._splitSpeed.z * this.currentSplitValue + node._splitSrcPos.z;
                node.parent.updateMatrixWorld();
                let invMat = node.parent.matrixWorld.clone().invert();
                let pos = new Vector3(x, y, z).applyMatrix4(invMat);
                node.position.copy(pos);
            }
            if (this.currentSplitValue == this.targetSplitValue) {
                this.running = false;

                if (this.isQuit == true) {
                    this.quit();
                    this.isQuit = false;
                }
            }
        }
    }
}
